﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Quick.EntityFrameworkCore.Operations;

public class MigrationOperations<TDbContext> where TDbContext : DbContext
{
    protected virtual ILogger _logger { get; set; }
    protected virtual IServiceProvider _serviceProvider { get; set; }
    protected virtual string[] _args { get; set; }

    public MigrationOperations(ILogger<MigrationOperations<TDbContext>> logger,
        IServiceProvider serviceProvider,
        string[] args)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
        _args = args;
    }

    public IEnumerable<MigrationInfo> GetMigrations(string? connectionString = null, bool noConnect = true)
    {
        return Build(_args).GetMigrations(typeof(TDbContext).FullName, connectionString, noConnect);
    }

    public string ScriptMigrations(string? fromMigration, string? toMigration, MigrationsSqlGenerationOptions options)
    {
        return Build(_args).ScriptMigration(fromMigration, toMigration, options, typeof(TDbContext).FullName);
    }

    private MigrationsOperations Build(params string[] args)
    {
        var db = _serviceProvider.GetRequiredService<TDbContext>();

        if (db is null)
        {
            throw new InvalidOperationException($"无法实例化DbContext: {typeof(TDbContext).FullName}");
        }

        var assembly = typeof(TDbContext).Assembly;
        var migrationsAssembly = db.GetService<IMigrationsAssembly>().Assembly;

        var logger = _serviceProvider.GetRequiredService<ILogger<DesignTimeServicesBuilder>>();
        var reporter = new OperationLogger(logger);

        //var designTimeServiceBuilder = new DesignTimeServicesBuilder(assembly, migrationsAssembly, reporter, []);

        var operations = new MigrationsOperations(
            reporter,
            assembly,
            migrationsAssembly,
            "",
            null,
            null,
            true,
            args);
        return operations;
    }
}
